package urjc.as.emergencies.client;

import java.awt.GridLayout;

import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTree;
import javax.swing.event.TreeSelectionEvent;
import javax.swing.event.TreeSelectionListener;
import javax.swing.tree.DefaultMutableTreeNode;
import javax.swing.tree.DefaultTreeModel;
import javax.swing.tree.TreePath;
import javax.swing.tree.TreeSelectionModel;

import urjc.as.emergencies.client.jpanels.missions.PanelHistorial;
import urjc.as.emergencies.client.jpanels.missions.PanelMission;
import urjc.as.emergencies.client.jpanels.missions.PanelMissions;
import urjc.as.emergencies.client.jpanels.missions.PanelPatientInfo;
import urjc.as.emergencies.client.jpanels.missions.ambulances.PanelAmbulance;
import urjc.as.emergencies.client.jpanels.missions.ambulances.PanelAmbulances;
import urjc.as.emergencies.data.Ambulance;
import urjc.as.emergencies.data.Historial;
import urjc.as.emergencies.data.ListaAmbulancias;
import urjc.as.emergencies.data.Mission;
import urjc.as.emergencies.data.MissionList;
import urjc.as.emergencies.data.PatientInfo;

/**
	 * Implementa un árbol dinámico con nodos que pueden ser creados y borrados
	 */
	public class DynamicTree extends JPanel implements TreeSelectionListener {

		// ////////// ATTRIBUTES

		/**
		 * 
		 */
		private final Client client;

		private static final long serialVersionUID = -7798027249538891647L;

		/**
		 * Raíz del árbol
		 */
		protected DefaultMutableTreeNode rootNode;
		/**
		 * Modelo del árbol
		 */
		protected DefaultTreeModel treeModel;

		// ////////// CONSTRUCTOR

		/**
		 * Constructor, crea el árbol de nodos y añade el nodo raíz.
		 * @param client TODO
		 */
		public DynamicTree(Client client) {
			super(new GridLayout(1, 0));
			this.client = client;

			// Creamos el nodo raíz del árbol
			Node root = new Node("Summa112", "http://localhost:8080/summa");

			root.setType(Node.SUMMA);

			rootNode = new DefaultMutableTreeNode(root);
			treeModel = new DefaultTreeModel(rootNode);

			// Configuramos el árbol
			this.client.tree = new JTree(treeModel);
			this.client.tree.setEditable(true);
			this.client.tree.getSelectionModel().setSelectionMode(
					TreeSelectionModel.SINGLE_TREE_SELECTION);
			this.client.tree.setShowsRootHandles(true);
			this.client.tree.addTreeSelectionListener(this);

			JScrollPane scrollPane = new JScrollPane(this.client.tree);
			add(scrollPane);

			insertaNodosIniciales();

		}

		
		public void deleteNode(DefaultMutableTreeNode node) {
			treeModel.removeNodeFromParent(node);
		}
		
		private void insertaNodosIniciales() {

			// Nodo misiones
			Node ruta = new Node("missions", "http://localhost:8080/missions");
			ruta.setType(Node.MISSIONS);
			DefaultMutableTreeNode nod = new DefaultMutableTreeNode(ruta);

			// Insertamos los nuevos nodos en el árbol
			treeModel.insertNodeInto(nod, rootNode, rootNode.getChildCount());
			this.client.tree.scrollPathToVisible(new TreePath(nod.getPath()));

			// Nodo misiones
			Node ruta2 = new Node("ambulancias",
					"http://localhost:8080/ambulancias");
			ruta2.setType(Node.AMBULANCES);
			DefaultMutableTreeNode nod2 = new DefaultMutableTreeNode(ruta2);

			// Insertamos los nuevos nodos en el árbol
			treeModel.insertNodeInto(nod2, rootNode, rootNode.getChildCount());
			this.client.tree.scrollPathToVisible(new TreePath(nod2.getPath()));
		}

//		public void deleteNode(DefaultMutableTreeNode node) {
//			treeModel.removeNodeFromParent(node);
//		}

		/**
		 * Manejador de eventos para selecciones de nodos en el árbol
		 */
		@Override
		public void valueChanged(TreeSelectionEvent arg0) {

			// Capturamos el nodo que ha sido seleccionado
			DefaultMutableTreeNode node = (DefaultMutableTreeNode) this.client.tree
					.getLastSelectedPathComponent();

			if (node == null)
				return;

			// Capturamos la información almacenada en el nodo
			Node nodeInfo = (Node) node.getUserObject();

			// Aquí comprobamos el tipo de nodo y actuamos en consecuencia
			// es el selector principal
			switch (nodeInfo.getType()) {
			case (Node.MISSIONS):
				// Nodo missions seleccionado
				processNodeMissions(nodeInfo, node);
				break;
			case (Node.HISTORIAL):
				// Nodo historial seleccionado
				processNodeHistorial(nodeInfo);
				break;
			case (Node.PATIENTINFO):
				// Nodo Información del paciente seleccionado
				processNodePatientInfo(nodeInfo, node);
				break;
			case (Node.MISSION):
				// Nodo mission
				processNodeMission(nodeInfo, node);
				break;
			case Node.AMBULANCES:
				// Nodo ambulancias seleccionado
				processNodeAmbulances(nodeInfo, node);
				break;
			case Node.AMBULANCE:
				// Nodo ambulancia seleccionado
				processNodeAmbulance(nodeInfo, node);
				break;
			default:
				this.client.deletePanel();
			}

		}

		// / ///////MANEJADORES DE NODOS

		/**
		 * Procesa todo lo relacionado con las misiones. Al final de este método
		 * tendremos una llamada a mostrar el panel que nos interesa.
		 * 
		 * @param nodeInfo
		 */
		private void processNodeMissions(Node nodeInfo,
				DefaultMutableTreeNode nodetree) {
			// Obtenemos una representación del nodo misiones
			MissionList missions = (MissionList) CommToolkit
					.getRepresentation(nodeInfo.getUri());

			// Mostramos el XML en el panel de texto
			this.client.text.append(missions.serializar());

			// Construimos el árbol que tenemos por debajo
			// Para ello:
			// - Obtenemos la representación de cada misión
			// - Añadimos el nodo
			for (String missionUri : missions.getMissionsList()) {
				Mission mission = (Mission) CommToolkit
						.getRepresentation(missionUri);

				// Creamos el nodo
				Node node = new Node("mission" + mission.getIdMision(), mission
						.getUri());
				node.setType(Node.MISSION);

				// Actualizaremos las carpetas a partir de dicha representación
				redrawTree(nodeInfo, nodetree, missionUri, Node.MISSION);

			}

			showMissionsPanel(missions);
		}

		private void processNodePatientInfo(Node nodeInfo,
				DefaultMutableTreeNode node) {
			// Obtenemos la representacion del recurso "informacion paciente"
			PatientInfo patient = (PatientInfo) CommToolkit
					.getRepresentation(nodeInfo.getUri());
			this.client.text.append(patient.serializar());

			// Actualizar la representacion del arbol
			if (patient.getHistorial() != null) {
				redrawTree(nodeInfo, node, patient.getHistorial(),
						Node.HISTORIAL);
			}

			showPatientInfoPanel(patient);
		}

		private void processNodeHistorial(Node nodeInfo) {
			// Obtenemos una representacion del recurso historial
			Historial historial = (Historial) CommToolkit
					.getRepresentation(nodeInfo.getUri());
			this.client.text.append(historial.serializar());

			showHistorialPanel(historial);

		}

		private void processNodeMission(Node nodeInfo,
				DefaultMutableTreeNode node) {
			// Obtenemos una representacion del recurso mision
			Mission mission = (Mission) CommToolkit.getRepresentation(nodeInfo
					.getUri());
			this.client.text.append(mission.serializar());

			// Actualizar la representacion del arbol
			if (mission.getAmbulance() != null) {
				redrawTree(nodeInfo, node, mission.getAmbulance(),
						Node.AMBULANCE);
			}

			if (mission.getPatientInformation() != null) {
				redrawTree(nodeInfo, node, mission.getPatientInformation(),
						Node.PATIENTINFO);
			}

			showMissionPanel(mission);
		}

		/**
		 * 
		 * @param nodeInfo
		 * @param node
		 */
		private void processNodeAmbulances(Node nodeInfo,
				DefaultMutableTreeNode node) {
			// Obtenemos una representación de la lista de ambulancias
			ListaAmbulancias ambulances = (ListaAmbulancias) CommToolkit
					.getRepresentation(nodeInfo.getUri());
			this.client.text.append(ambulances.serializar());

			// Actualizaremos las carpetas a partir de dicha representación
			for (String ambulance : ambulances.getListaAmbulancias()) {
				redrawTree(nodeInfo, node, ambulance, Node.AMBULANCE);
			}
			showAmbulancesPanel();
		}

		/**
		 * 
		 * @param nodeInfo
		 * @param node
		 */
		private void processNodeAmbulance(Node nodeInfo,
				DefaultMutableTreeNode node) {
			// Obtenemos una representación de la lista de ambulancias
			Ambulance ambulance = (Ambulance) CommToolkit
					.getRepresentation(nodeInfo.getUri());
			this.client.text.append(ambulance.serializar());

			// Muestra panel para hacer patches
			showAmbulancePanel(ambulance);
		}

		/**
		 * Repinta el arbol
		 * 
		 * @param nodeInfo
		 * @param node
		 * @param nodeName
		 * @param type
		 */
		private void redrawTree(Node nodeInfo, DefaultMutableTreeNode node,
				String nodeName, int type) {
			boolean found = false;
			if (!node.isLeaf()) {
				int i = 0;
				while (!found && i < node.getChildCount()) {
					DefaultMutableTreeNode child = (DefaultMutableTreeNode) node
							.getChildAt(i);
					if (((Node) child.getUserObject()).getUri()
							.equals(nodeName)) {
						found = true;
					}
					i++;

				}
			}

			if (!found || node.isLeaf()) {
				// Creamos el nodo correspondiente a la carpeta
				String[] cadena = nodeName.split("/");
				Node ruta = new Node(cadena[cadena.length - 1], nodeName);
				ruta.setType(type);
				DefaultMutableTreeNode nod = new DefaultMutableTreeNode(ruta);

				// Insertamos el nodo en el árbol
				treeModel.insertNodeInto(nod, node, node.getChildCount());
				this.client.tree.scrollPathToVisible(new TreePath(nod.getPath()));
			}
		}

		public DefaultMutableTreeNode getLastSelectedNode() {
			return (DefaultMutableTreeNode) this.client.tree
			.getLastSelectedPathComponent();

		}
		/**
		 * Repinta el arbol
		 * @param uri
		 * @param type
		 */
		public void redraw(String uri, int type) {
			DefaultMutableTreeNode node = (DefaultMutableTreeNode) this.client.tree
					.getLastSelectedPathComponent();

			if(node != null){
				Node nodeInfo = (Node) node.getUserObject();
				this.redrawTree(nodeInfo, node, uri, type);
			}
		}

		// /////// MOSTRADORES DE PANELES

		// Mostrador de panel Misiones
		private void showMissionsPanel(MissionList missionsList) {
			JPanel panelMissions = new PanelMissions(this.client.text, missionsList, this);
			this.client.treeOptions.remove(1);
			this.client.treeOptions.add(panelMissions, 1);
			this.client.treeOptions.updateUI();

		}

		// Mostrador de panel Mision
		private void showMissionPanel(Mission mission) {
			JPanel panelMission = new PanelMission(this.client.text, mission, this);
			this.client.treeOptions.remove(1);
			this.client.treeOptions.add(panelMission, 1);
			this.client.treeOptions.updateUI();
		}

		private void showPatientInfoPanel(PatientInfo infoPatient) {
			JPanel panelPatientInfo = new PanelPatientInfo(this.client.text, infoPatient);
			this.client.treeOptions.remove(1);
			this.client.treeOptions.add(panelPatientInfo, 1);
			this.client.treeOptions.updateUI();
		}

		private void showHistorialPanel(Historial historial) {
			JPanel panelHistorial = new PanelHistorial(this.client.text, this.client.tree, historial);
			this.client.treeOptions.remove(1);
			this.client.treeOptions.add(panelHistorial, 1);
			this.client.treeOptions.updateUI();
		}

		private void showAmbulancesPanel() {
			JPanel panelAmbulance = new PanelAmbulances(this.client.text, this.client.tree, this);
			this.client.treeOptions.remove(1);
			this.client.treeOptions.add(panelAmbulance, 1);
			this.client.treeOptions.updateUI();
		}

		private void showAmbulancePanel(Ambulance ambulance) {
			JPanel panelAmbulance = new PanelAmbulance(this.client.text, this.client.tree, ambulance, this);
			this.client.treeOptions.remove(1);
			this.client.treeOptions.add(panelAmbulance, 1);
			this.client.treeOptions.updateUI();
		}

	}